package master

import (
	"encoding/json"
	"gitee.com/Cookie_XiaoD/crontab/common"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strconv"
	"time"
)

type ApiServer struct {
	httpServer *http.Server
}

var G_apiServer *ApiServer

//InitApiServer 初始化ApiServer，用于处理http请求
func InitApiServer() (err error) {
	//初始化ApiServer
	//1.定义路由
	//2.监听端口
	//3.创建Http服务器
	//4.将http服务器赋值给ApiServer单例

	var (
		mux        *http.ServeMux
		listener   net.Listener
		httpServer *http.Server
		staticDir http.Dir
		staticHandler http.Handler
	)

	//1
	mux = http.NewServeMux()
	mux.HandleFunc("/jobs/save", handSaveJob)
	mux.HandleFunc("/jobs/delete", handDeleteJob)
	mux.HandleFunc("/jobs/list", handListJob)
	mux.HandleFunc("/jobs/kill", handKillJob)

	//需要支持静态资源
	//1,指定静态资源根目录
	staticDir=http.Dir(G_config.WebRoot)
	//2.创建静态文件handler
	staticHandler=http.FileServer(staticDir)
	//3.针对/的请求，走静态资源处理
	//需要注意的是 比如请求的是 /index.html，满足路由规则，但是/index.html直接交给handler是无法处理的，
	//handler需要的是index.html，所以利用http.StripPrefix截断开头部分
	mux.Handle("/",http.StripPrefix("/",staticHandler))


	//2.
	if listener, err = net.Listen("tcp", ":"+strconv.Itoa(G_config.ApiPort)); err != nil {
		return
	}
	//3
	httpServer = &http.Server{
		ReadTimeout:  time.Duration(G_config.ApiReadTimeout) * time.Millisecond,
		WriteTimeout: time.Duration(G_config.ApiWriteTimeout) * time.Millisecond,
		Handler:      mux,
	}
	//TODO:我觉得这里单例的实现有问题，后面再改,应该采用线程安全，且外部无法在创建apiserver实例的情况
	G_apiServer = &ApiServer{
		httpServer,
	}

	//TODO:如果有异常，如何处理
	go httpServer.Serve(listener)

	return

}

func sendResp(w http.ResponseWriter, r *http.Request, errno int, msg string, data interface{}) {
	var (
		resp []byte
		err  error
	)
	if resp, err = common.BuildResponse(errno, msg, data); err != nil {
		//不可能发生
		return
	}

	w.Write(resp)

}

func handSaveJob(w http.ResponseWriter, r *http.Request) {
	log.Println("保存任务")
	var (
		err    error
		body   []byte
		oldJob *common.Job
	)

	body, ok := checkRequest(w, r)
	if !ok {
		return
	}

	var job common.Job

	if err := json.Unmarshal(body, &job); err != nil {
		return
	}

	if oldJob, err = G_JobMgr.SaveJob(&job); err != nil {
		return
	}

	sendResp(w, r, 0, "保存成功", oldJob)

}

func checkRequest(w http.ResponseWriter, r *http.Request) (body []byte, ok bool) {
	w.Header().Set("content-type", "text/json")
	if r.Method != "POST" {
		sendResp(w, r, -1, "仅支持Post请求", nil)
		return
	}

	ct := r.Header.Get("Content-Type")
	if ct != "application/json" {
		sendResp(w, r, -2, "仅支持Post请求application/json", nil)
		return
	}

	var (
		err error
	)

	if body, err = ioutil.ReadAll(r.Body); err != nil {
		sendResp(w, r, -3, "解析Body失败", nil)
		return
	}

	return body, true

}

func handDeleteJob(w http.ResponseWriter, r *http.Request) {
	log.Println("删除任务")
	var (
		err       error
		oldJob    *common.Job
		delJobReq common.DelJobReq
	)

	body, ok := checkRequest(w, r)
	if !ok {
		return
	}

	if err := json.Unmarshal(body, &delJobReq); err != nil {
		return
	}

	if oldJob, err = G_JobMgr.DeleteJob(delJobReq.JobName); err != nil {
		return
	}

	sendResp(w, r, 0, "删除成功", oldJob)

}

func handListJob(w http.ResponseWriter, r *http.Request) {
	log.Println("获取任务列表")
	var (
		err  error
		jobs []*common.Job
	)

	if jobs, err = G_JobMgr.ListJob(); err != nil {
		return
	}

	sendResp(w, r, 0, "获取成功", jobs)

}

func handKillJob(w http.ResponseWriter, r *http.Request) {
	log.Println("强杀任务")
	var (
		oldJob    *common.Job
		killJobReq common.KillJobReq
	)

	body, ok := checkRequest(w, r)
	if !ok {
		return
	}

	if err := json.Unmarshal(body, &killJobReq); err != nil {
		return
	}

	if err := G_JobMgr.KillJob(killJobReq.JobName); err != nil {
		return
	}

	sendResp(w, r, 0, "强杀任务成功", oldJob)

}
